package com.acme.javaschool.intense.sems.sem3logging;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

public class YetAnotherLogger {
    private static final HashMap<AppenderType, Appender> APPENDERS = new HashMap<>();

    private final String name;
    private final List<AppenderType> activeAppenderTypes = new ArrayList<>();

    private volatile Level level;

    public YetAnotherLogger(String name, Level level) {
        this.name = name;
        this.level = level;
    }

    public void log(Level level, String message, Object... objects) {
        if (isLevelEnabled(level)) {
            if (message != null) {
                Object[] output = parseFormat(message, objects);

                for (AppenderType type : activeAppenderTypes) {
                    APPENDERS.get(type).submit(output);
                }
            }
        }
    }

    private Object[] parseFormat(String message, Object... objects) {
        message = getLevel() + " " + message;

        if (objects != null) {
            message = message.replaceAll("%t", Thread.currentThread().toString());
            message = message.replaceAll("%d", new Date().toString());
            message = message.replaceAll("%l", getName());
            String[] messageParts = message.split("\\{\\}", objects.length + 1);
            Object[] parts = new String[messageParts.length + objects.length];

            int min = Math.min(messageParts.length, objects.length);
            for (int i = 0; i < min; i++) {
                parts[2 * i] = messageParts[i];
                parts[2 * i + 1] = objects[i];
            }

            for (int i = min; i < Math.max(messageParts.length, objects.length); i++) {
                parts[i + min] = messageParts.length < objects.length ? objects[i] : messageParts[i];
            }

            return parts;
        }
        return new Object[] {message};
    }

    public synchronized void setLevel(Level level) {
        this.level = level;
    }

    public Level getLevel() {
        return this.level;
    }

    public void addAppender(AppenderType type) {
        if (appenderIsInit(type)) {
            activeAppenderTypes.add(type);
        }
    }

    public void addAppender(Appender appender) {
        if (!appenderIsInit(appender.type)) {
            APPENDERS.put(appender.type, appender);
            activeAppenderTypes.add(appender.type);
        }
    }

    public boolean appenderIsInit(AppenderType type) {
        return APPENDERS.get(type) != null;
    }

    public String getName() {
        return this.name;
    }

    public boolean isLevelEnabled(Level level) {
        return level.severity >= getLevel().severity;
    }

    private void show(Object[] os) {
        for (Object o : os) {
            System.out.print(o + "_");
        }
        System.out.println();
    }

}
